#include "GVector2.h"

#include "GMath.h"

namespace GMath
{

	const GVector2 GVector2::Zero	= GVector2(0.0f, 0.0f);
	const GVector2 GVector2::One	= GVector2(1.0f, 1.0f);;
	const GVector2 GVector2::UnitX	= GVector2(1.0f, 0.0f);;
	const GVector2 GVector2::UnitY	= GVector2(0.0f, 1.0f);;
	const GVector2 GVector2::Min	= GVector2(G_FLOAT_MIN, G_FLOAT_MIN);
	const GVector2 GVector2::Max	= GVector2(G_FLOAT_MAX, G_FLOAT_MAX);


	GVector2::GVector2()
	{		
		x = 0.0f;
		y = 0.0f;
	}

	GVector2::GVector2(float Vx, float Vy)
	{
		x = Vx;
		y = Vy;
	}	

	GVector2::operator float* ()
	{
		return Arr;
	}

	GVector2::operator const float* ()const
	{
		return Arr;
	}

	float GVector2::Lenght() const
	{
		return SqrtF(x * x + y * y);
	}

	float GVector2::LenghtSqr() const
	{
		return x * x + y * y;
	}

	float GVector2::Distance(const GVector2& Vector) const
	{
		float Dx = Vector.x - x;
		float Dy = Vector.y - y;

		return SqrtF(Dx * Dx + Dy * Dy);
	}

	float GVector2::DistanceSqr(const GVector2& Vector) const
	{
		float Dx = Vector.x - x;
		float Dy = Vector.y - y;

		return Dx * Dx + Dy * Dy;
	}

	void GVector2::Maximum(OUTPUT GVector2& Output, const GVector2& Vector1, const GVector2& Vector2)
	{
		Output.x = Vector1.x > Vector2.x ? Vector1.x : Vector2.x;
		Output.y = Vector1.y > Vector2.y ? Vector1.y : Vector2.y;
	}

	void GVector2::Minimum(OUTPUT GVector2& Output, const GVector2& Vector1, const GVector2& Vector2)
	{
		Output.x = Vector1.x < Vector2.x ? Vector1.x : Vector2.x;
		Output.y = Vector1.y < Vector2.y ? Vector1.y : Vector2.y;
	}

	void GVector2::Saturate()
	{
		Clamp(GVector2::Zero, GVector2::One);
	}

	void GVector2::Saturate(OUTPUT GVector2& Output, const GVector2& Vector)
	{
		GVector2::Clamp(Output, Vector, GVector2::Zero, GVector2::One);
	}

	void GVector2::Normalize()
	{
		// Check zero case
		float InverseLenght = 1 / Lenght();

		x *= InverseLenght;
		y *= InverseLenght;
	}

	void GVector2::Normalize(OUTPUT GVector2& Output, const GVector2& Vector)
	{
		// Check zero case
		float InverseLenght = 1 / Vector.Lenght();

		Output.x = Vector.x * InverseLenght;
		Output.y = Vector.y * InverseLenght;
	}

	void GVector2::Absolute()
	{
		x = AbsF(x);
		y = AbsF(y);
	}

	void GVector2::Absolute(OUTPUT GVector2& Output, const GVector2& Vector)
	{
		Output.x = AbsF(Vector.x);
		Output.y = AbsF(Vector.y);
	}

	void GVector2::Scale(float Value)
	{
		x *= Value;
		y *= Value;
	}

	void GVector2::Scale(OUTPUT GVector2& Output, const GVector2& Vector, float Value)
	{
		Output.x = Vector.x * Value;
		Output.y = Vector.y * Value;
	}

	void GVector2::Clamp(const GVector2& LimitLow, const GVector2& LimitUp)
	{
		if (x > LimitUp.x)
		{
			x = LimitUp.x;
		}
		else if (x < LimitLow.x)
		{
			x = LimitLow.x;
		}

		if (y > LimitUp.y)
		{
			y = LimitUp.y;
		}
		else if (y < LimitLow.y)
		{
			y = LimitLow.y;
		}
	}

	void GVector2::Clamp(OUTPUT GVector2& Output, const GVector2& Vector, const GVector2& LimitLow, const GVector2& LimitUp)
	{
		if (Vector.x > LimitUp.x)
		{
			Output.x = LimitUp.x;
		}
		else if (Vector.x < LimitLow.x)
		{
			Output.x = LimitLow.x;
		}

		if (Vector.y > LimitUp.y)
		{
			Output.y = LimitUp.y;
		}
		else if (Vector.y < LimitLow.y)
		{
			Output.y = LimitLow.y;
		}
	}
	
	void GVector2::Lerp(const GVector2& Vector, float Amount)
	{
		x += (Vector.x - x) * Amount;
		y += (Vector.y - y) * Amount;
	}

	void GVector2::Lerp(OUTPUT GVector2& Output, const GVector2& VectorA, const GVector2& VectorB, float Amount)
	{
		Output.x = VectorA.x + (VectorB.x - VectorA.x) * Amount;
		Output.y = VectorA.y + (VectorB.y - VectorA.y) * Amount;
	}

	float GVector2::Dot(const GVector2& Vector) const
	{
		return x * Vector.x + y * Vector.y;
	}

	float GVector2::Dot(const GVector2& VectorA, const GVector2& VectorB)
	{
		return VectorA.x * VectorB.x + VectorA.y * VectorB.y;
	}

	float GVector2::Cross(const GVector2& Vector) const
	{
		return x * Vector.y - y * Vector.x;
	}

	float GVector2::Cross(const GVector2& VectorA, const GVector2& VectorB)
	{
		return VectorA.x * VectorB.y - VectorA.y * VectorB.x;
	}

	GVector2& GVector2::operator += (const GVector2& Vector)
	{
		x += Vector.x;
		y += Vector.y;
		return *this;
	}

	GVector2& GVector2::operator -= (const GVector2& Vector)
	{
		x -= Vector.x;
		y -= Vector.y;
		return *this;
	}

	GVector2& GVector2::operator *= (const GVector2& Vector)
	{
		x *= Vector.x;
		y *= Vector.y;
		return *this;
	}
	GVector2& GVector2::operator /= (const GVector2& Vector)
	{
		x /= Vector.x;
		y /= Vector.y;
		return *this;
	}

	GVector2& GVector2::operator *= (const float Value)
	{
		x *= Value;
		y *= Value;
		return *this;
	}
	GVector2& GVector2::operator /= (const float Value)
	{
		float Inverse = 1.0f / Value;
		x *= Inverse;
		x *= Inverse;
		return *this;
	}

	GVector2 GVector2::operator + () const
	{
		return *this;
	}
	GVector2 GVector2::operator - () const
	{
		return GVector2( -x, -y);
	}

	GVector2 GVector2::operator + (const GVector2& Vector) const
	{
		return GVector2(x + Vector.x, y + Vector.y);
	}

	GVector2 GVector2::operator - (const GVector2& Vector) const
	{
		return GVector2(x - Vector.x, y - Vector.y);
	}

	GVector2 GVector2::operator * (const GVector2& Vector) const
	{
		return GVector2(x * Vector.x, y * Vector.y);
	}

	GVector2 GVector2::operator / (const GVector2& Vector) const
	{
		return GVector2(x / Vector.x, y / Vector.y);
	}

	GVector2 GVector2::operator * (float Value) const
	{
		return GVector2(x * Value, y * Value);
	}

	GVector2 GVector2::operator / (float Value) const
	{
		float Inverse = 1.0f / Value;
		return GVector2(x * Inverse, y * Inverse);
	}

	bool GVector2::operator == (const GVector2& Vector) const
	{
		return	EqualF(x, Vector.x) &&
				EqualF(y, Vector.y);
	}

	bool GVector2::operator != (const GVector2& Vector) const
	{
		return !operator==(Vector);
	}

	GVector2 operator * (float Value, const GVector2& Vector)
	{
		return GVector2(Value * Vector.x, Value * Vector.y);
	}

	GVector2 operator / (float Value, const GVector2& Vector)
	{
		return GVector2(Value / Vector.x, Value / Vector.y);
	}

}